#ifndef __HWIRQ_H
#define __HWIRQ_H

#include "platform.h"
#include "riscv_asm.h"


/* Machine-mode Interrupt Enable */
#define MIE_MEIE (1 << 11) // external
#define MIE_MTIE (1 << 7)  // time
#define MIE_MSIE (1 << 3)  // soft

/* Machine Status Register, mstatus */
#define MSTATUS_MIE (1 << 3)
#define MSTATUS_SIE (1 << 1)

/*
 * This machine puts platform-level interrupt controller (PLIC) here.
 * Here only list PLIC registers in Machine mode.
 * see https://github.com/qemu/qemu/blob/master/include/hw/riscv/virt.h
 * #define VIRT_PLIC_HART_CONFIG "MS"
 * #define VIRT_PLIC_NUM_SOURCES 127
 * #define VIRT_PLIC_NUM_PRIORITIES 7
 * #define VIRT_PLIC_PRIORITY_BASE 0x04
 * #define VIRT_PLIC_PENDING_BASE 0x1000
 * #define VIRT_PLIC_ENABLE_BASE 0x2000
 * #define VIRT_PLIC_ENABLE_STRIDE 0x80
 * #define VIRT_PLIC_CONTEXT_BASE 0x200000
 * #define VIRT_PLIC_CONTEXT_STRIDE 0x1000
 * #define VIRT_PLIC_SIZE(__num_context) \
 *     (VIRT_PLIC_CONTEXT_BASE + (__num_context) * VIRT_PLIC_CONTEXT_STRIDE)
 */

#define PLIC_PRIORITY(hwirq)		(PLIC_BASE + (hwirq) * 4)
#define	PLIC_PENDING(hwirq)			(PLIC_BASE + 0x1000 + ((hwirq) / 32) * 4)
#define PLIC_MENABLE(hart, hwirq)	(PLIC_BASE + 0x2000 + (hart) * 0x80 + ((hwirq) / 32) * 4)
#define	PLIC_MTHRESHOLD(hart)		(PLIC_BASE + 0x200000 + (hart) * 0x1000)
#define	PLIC_MCLAIM(hart)			(PLIC_BASE + 0x200004 + (hart) * 0x1000)
#define PLIC_MCOMPLETE(hart)		(PLIC_BASE + 0x200004 + (hart) * 0x1000)


/*
 * voidore Local INTerruptor (CLINT) block holds memory-mapped control and
 * status registers associated with software and timer interrupts.
 * QEMU-virt reuses sifive configuration for CLINT.
 * enum {
 * 		SIFIVE_SIP_BASE     = 0x0,
 * 		SIFIVE_TIMECMP_BASE = 0x4000,
 * 		SIFIVE_TIME_BASE    = 0xBFF8
 * 	};
 *
 * 	enum {
 * 		SIFIVE_CLINT_TIMEBASE_FREQ = 10000000
 * 	};
 *
 * 	Notice:
 * 	The machine-level MSIP bit of mip register are written by accesses to
 * 	memory-mapped control registers, which are used by remote harts to provide
 * 	machine-mode interprocessor interrupts.
 * 	For QEMU-virt machine, Each msip register is a 32-bit wide WARL register
 * 	where the upper 31 bits are tied to 0. The least significant bit is
 * 	reflected in the MSIP bit of the mip CSR. We can write msip to generate
 * 	machine-mode software interrupts. A pending machine-level software
 * 	interrupt can be cleared by writing 0 to the MSIP bit in mip.
 * 	On reset, each msip register is cleared to zero.
 */

#define CLINT_MSIP(hartid)			(CLINT_BASE + 4 * (hartid))
#define CLINT_MTIMECMP(hartid)		(CLINT_BASE + 0X4000 + 8 * (hartid))
#define CLINT_MTIME					(CLINT_BASE + 0xbff8)
#define CLINT_MSIP_H0				(CLINT_BASE + 4 * 0)



inline void enable_global_interrupt()
{
	/* enable machine-mode global interrupts */
	csr_write(mstatus, csr_read(mstatus) | MSTATUS_MIE);
}

inline void enable_msoft_interrupt()
{
	/* enable machine-mode soft interrupts */
	csr_write(mie, csr_read(mie)|MIE_MSIE);
}



void plic_init(void);
uint32_t plic_claim(void);
void plic_complete(uint32_t hwirq);

#endif
